#include "head.h"

int exit_pipeFd[2];//退出管道

void exit_sigfunc(int signum)
{
    printf("要有序退出了\n");
    write(exit_pipeFd[1],"1",1);
}

int main(int argc,char *argv[])
{
    if(argc!=4)
    {
        printf("./process_pool IP PORT PROCESS_NUM\n");
        return -1;
    }
    pipe(exit_pipeFd);
    signal(SIGUSR1,exit_sigfunc);

    int childNum=atoi(argv[3]);//子进程数目
    processData_t *workerList=(processData_t *)calloc(childNum,sizeof(processData_t));
    make_child(workerList,childNum);//创建好了子进程

    int sock_fd;
    tcp_init(argv[1],argv[2],&sock_fd);

    //注册监控sock_fd
    int epfd=epoll_create(1);
    epoll_add(epfd,sock_fd);

    //注册监控退出管道的读端
    epoll_add(epfd,exit_pipeFd[0]);

    //监控每个子进程的管道对端
    int i;
    for(i=0;i<childNum;i++)
    {
        epoll_add(epfd,workerList[i].pipeFd);
    }
    int ready_fd_num,new_fd;
    struct epoll_event *evs=(struct epoll_event *)calloc(childNum+2,
        sizeof(struct epoll_event));
    
    struct sockaddr_in clientAddr;
    int addrLen,j,finish_flag;
    while(1)
    {
        ready_fd_num=epoll_wait(epfd,evs,childNum+2,-1);
        for(i=0;i<ready_fd_num;i++)//i遍历的是多少描述符就绪
        {
            //如果sock_fd可读
            if(sock_fd==evs[i].data.fd)
            {
                addrLen=sizeof(clientAddr);
                new_fd=accept(sock_fd,(struct sockaddr*)&clientAddr,&addrLen);
                printf("task coming ip=%s,port=%d\n",inet_ntoa(clientAddr.sin_addr),
                    ntohs(clientAddr.sin_port));
                //找到非忙碌的子进程，把任务派给它
                for(j=0;j<childNum;j++)
                {
                    if(workerList[j].status==FREE)
                    {
                        sendFd(workerList[j].pipeFd,new_fd,0);//发new_fd给对应子进程
                        workerList[j].status=BUSY;//把其标记为busy
                        printf("%d 派给 %d 子进程\n",new_fd,workerList[j].pid);
                        break;
                    }
                }
                close(new_fd);//sendFd时，引用计数加1，这时要让引用计数减1
            }else if(evs[i].data.fd==exit_pipeFd[0])//父进程知道要关店了
            {
                close(sock_fd);//不再接收新的请求
                //给每个子进程发送下班的通知
                for(j=0;j<childNum;j++)
                {
                    sendFd(workerList[j].pipeFd,0,1);//通知每个子进程退出
                }
                for(j=0;j<childNum;j++)//等着所有子进程退出（服务员下班）
                {
                    wait(NULL);
                }
                printf("退出\n");
                exit(0);
            }else{
                for(j=0;j<childNum;j++)
                {
                    if(evs[i].data.fd==workerList[j].pipeFd)
                    {
                        //有子进程通知父进程它完成任务了
                        read(workerList[j].pipeFd,&finish_flag,sizeof(int));//把管道数据读出来
                        workerList[j].status=FREE;//把对应子进程标记为非忙碌
                        printf("%d process finish task\n",workerList[j].pid);
                        break;
                    }
                }
            }
        }
    }
}
